#include "bsp.h"

#ifdef USE_PRINTF
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#endif
#ifdef USE_GPIO
/***************************************************************************************************
* GPIO API
*/
static void _g_set_clk(uint32_t gpiox)
{
        switch(gpiox)
    {
        case GPIOA:rcu_periph_clock_enable(RCU_GPIOA);break;
        case GPIOB:rcu_periph_clock_enable(RCU_GPIOB);break;
        case GPIOC:rcu_periph_clock_enable(RCU_GPIOC);break;
        case GPIOD:rcu_periph_clock_enable(RCU_GPIOD);break;
        case GPIOF:rcu_periph_clock_enable(RCU_GPIOF);break;
#ifndef GD32F3X0
        case GPIOE:rcu_periph_clock_enable(RCU_GPIOE);break;
#ifndef GD32F10X
        case GPIOG:rcu_periph_clock_enable(RCU_GPIOG);break;
        case GPIOH:rcu_periph_clock_enable(RCU_GPIOH);break;
        case GPIOI:rcu_periph_clock_enable(RCU_GPIOI);break;
#endif
#endif
        default:break;
    }
}

static void _g_afio_gpio_init(AFIO_GPIO *afio_gpio)
{
    _g_set_clk(afio_gpio->gpiox);

#if defined(GD32F10X) ||defined(GD32F20X)
    gpio_init(afio_gpio->gpiox, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,afio_gpio->gpio_pinx);
#else
	   gpio_af_set(afio_gpio->gpiox, afio_gpio->gpio_af, afio_gpio->gpio_pinx);
    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(afio_gpio->gpiox, GPIO_MODE_AF, GPIO_PUPD_PULLUP, afio_gpio->gpio_pinx);
    gpio_output_options_set(afio_gpio->gpiox, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, afio_gpio->gpio_pinx);
#endif
}

AFIO_GPIO new_afio_gpio(uint32_t gpiox,uint32_t gpio_pinx,uint32_t gpio_afx)
{
    AFIO_GPIO temp;
    temp.gpiox = gpiox;
    temp.gpio_pinx = gpio_pinx;
    temp.gpio_af = gpio_afx;
    temp.init = _g_afio_gpio_init;
    temp.init(&temp);
    return temp;
}

static void _g_outputport_init(OutputPort *outputport)
{
    _g_set_clk(outputport->gpiox);
#if defined(GD32F10X) ||defined(GD32F20X)
    gpio_init(outputport->gpiox, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,outputport->gpio_pinx);
#else
    gpio_mode_set(outputport->gpiox, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,outputport->gpio_pinx);
    gpio_output_options_set(outputport->gpiox, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,outputport->gpio_pinx);

#endif
}
 
static void _g_toggle(OutputPort *outputport)
{
    GPIO_OCTL(outputport->gpiox) ^= (uint32_t)outputport->gpio_pinx;
}

static void _g_setbit(OutputPort *outputport)
{
    gpio_bit_set(outputport->gpiox,outputport->gpio_pinx);
}

static void _g_resetbit(OutputPort *outputport)
{
    gpio_bit_reset(outputport->gpiox,outputport->gpio_pinx);
}

OutputPort new_outport(uint32_t gpiox,uint32_t gpio_pinx)
{
    OutputPort temp;
    temp.gpiox = gpiox;
    temp.gpio_pinx = gpio_pinx;
    temp.init = _g_outputport_init; 
    temp.set_bit = _g_setbit;
    temp.reset_bit = _g_resetbit;
    temp.toggle = _g_toggle;
    temp.init(&temp);
    return temp;
}

static void _g_input_init(InputPort *inputport)
{
    /* enable the key clock */
    _g_set_clk(inputport->gpiox);
#if defined(GD32F10X) ||defined(GD32F20X)
    /* configure button pin as input */
    gpio_init(inputport->gpiox, inputport->inputmode, GPIO_OSPEED_50MHZ,inputport->gpio_pinx);
#else
	   gpio_mode_set(inputport->gpiox, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP,inputport->gpio_pinx);
#endif
}

static void _g_exti_init(InputPort *inputport)
{
#ifdef GD32F4XX
    rcu_periph_clock_enable(RCU_SYSCFG);

    /* enable and set key EXTI interrupt to the lowest priority */
    uint8_t pin_source;
    uint8_t irqn;
    switch(inputport->gpio_pinx)
    {
        case GPIO_PIN_0:irqn  = EXTI0_IRQn;    pin_source = EXTI_SOURCE_PIN0; inputport->exit_line = EXTI_0;break;
        case GPIO_PIN_1:irqn  = EXTI1_IRQn;    pin_source = EXTI_SOURCE_PIN1; inputport->exit_line = EXTI_1;break;
        case GPIO_PIN_2:irqn  = EXTI2_IRQn;    pin_source = EXTI_SOURCE_PIN2;inputport->exit_line = EXTI_2;break;
        case GPIO_PIN_3:irqn  = EXTI3_IRQn;    pin_source = EXTI_SOURCE_PIN3;inputport->exit_line = EXTI_3;break;
        case GPIO_PIN_4:irqn  = EXTI4_IRQn;    pin_source = EXTI_SOURCE_PIN4;inputport->exit_line = EXTI_4;break;
        case GPIO_PIN_5:irqn  = EXTI5_9_IRQn;  pin_source = EXTI_SOURCE_PIN5;inputport->exit_line = EXTI_5;break;
        case GPIO_PIN_6:irqn  = EXTI5_9_IRQn;  pin_source = EXTI_SOURCE_PIN6;inputport->exit_line = EXTI_6;break;
        case GPIO_PIN_7:irqn  = EXTI5_9_IRQn;  pin_source = EXTI_SOURCE_PIN7;inputport->exit_line = EXTI_7;break;
        case GPIO_PIN_8:irqn  = EXTI5_9_IRQn;  pin_source = EXTI_SOURCE_PIN8;inputport->exit_line = EXTI_8;break;
        case GPIO_PIN_9:irqn  = EXTI5_9_IRQn;  pin_source = EXTI_SOURCE_PIN9;inputport->exit_line = EXTI_9;break;
        case GPIO_PIN_10:irqn = EXTI10_15_IRQn;pin_source = EXTI_SOURCE_PIN10;inputport->exit_line = EXTI_10;break;
        case GPIO_PIN_11:irqn = EXTI10_15_IRQn;pin_source = EXTI_SOURCE_PIN11;inputport->exit_line = EXTI_11;break;
        case GPIO_PIN_12:irqn = EXTI10_15_IRQn;pin_source = EXTI_SOURCE_PIN12;inputport->exit_line = EXTI_12;break;
        case GPIO_PIN_13:irqn = EXTI10_15_IRQn;pin_source = EXTI_SOURCE_PIN13;inputport->exit_line = EXTI_13;break;
        case GPIO_PIN_14:irqn = EXTI10_15_IRQn;pin_source = EXTI_SOURCE_PIN14;inputport->exit_line = EXTI_14;break;
        case GPIO_PIN_15:irqn = EXTI10_15_IRQn;pin_source = EXTI_SOURCE_PIN15;inputport->exit_line = EXTI_15;break;
        default:break;
    }
    uint8_t port_source;
    switch(inputport->gpiox)
    {
        case GPIOA:port_source = EXTI_SOURCE_GPIOA;break;
        case GPIOB:port_source = EXTI_SOURCE_GPIOB;break;
        case GPIOC:port_source = EXTI_SOURCE_GPIOC;break;
        case GPIOD:port_source = EXTI_SOURCE_GPIOD;break;
        case GPIOE:port_source = EXTI_SOURCE_GPIOE;break;
        case GPIOF:port_source = EXTI_SOURCE_GPIOF;break;
        case GPIOG:port_source = EXTI_SOURCE_GPIOG;break;
        case GPIOH:port_source = EXTI_SOURCE_GPIOH;break;
        case GPIOI:port_source = EXTI_SOURCE_GPIOI;break;
        default:break;
    }
    nvic_irq_enable(irqn , 0U, 2U);
    /* connect key EXTI line to key GPIO pin */
    syscfg_exti_line_config(port_source,pin_source);

    /* configure key EXTI line */
    exti_init(inputport->exit_line, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_interrupt_flag_clear(inputport->exit_line);
#endif
}

static uint8_t _g_read(InputPort *inputport)
{
    return gpio_input_bit_get(inputport->gpiox,inputport->gpio_pinx);
}

InputPort new_inputport(uint32_t gpiox,uint32_t gpio_pinx,uint8_t inputmode,uint8_t trig_type)
{
    InputPort temp;
    temp.gpiox = gpiox;
    temp.gpio_pinx = gpio_pinx;
    temp.inputmode = inputmode;
    temp.trig_type = trig_type;
    temp.init = _g_input_init;
    temp.read = _g_read;
    temp.init(&temp);    
    return temp;
}

InputPort new_inputport_interuput(uint32_t gpiox,uint32_t gpio_pinx,uint8_t trig_type,pfun callback,void *arg)
{
    InputPort temp;
    temp.gpiox = gpiox;
    temp.gpio_pinx = gpio_pinx;
    temp.init = _g_input_init;
    temp.read = _g_read;
    temp.exti_init = _g_exti_init;
    temp.callback = callback;
    temp.arg = arg;
    temp.init(&temp);
    temp.exti_init(&temp);
    return temp;
}

static void _g_opendrainport_init(OpenDrainPort *opendrainport)
{
    _g_set_clk(opendrainport->gpiox);
#if defined(GD32F10X) ||defined(GD32F20X)
    gpio_init(opendrainport->gpiox, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ,opendrainport->gpio_pinx);
#else
    gpio_mode_set(opendrainport->gpiox, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,opendrainport->gpio_pinx);
    gpio_output_options_set(opendrainport->gpiox, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,opendrainport->gpio_pinx);

#endif
}

OpenDrainPort new_opendrainport(uint32_t gpiox,uint32_t gpio_pinx)
{
    OpenDrainPort temp;
    temp.gpiox = gpiox;
    temp.gpio_pinx = gpio_pinx;
    temp.init = _g_opendrainport_init; 
	#ifndef GD32F10X
    temp.input = new_inputport(gpiox,gpio_pinx,0,0);
	#else
		temp.input = new_inputport(gpiox,gpio_pinx,GPIO_MODE_IPU,0);
	#endif
    temp.output = new_outport(gpiox,gpio_pinx);
    temp.read = (uint8_t(*)(OpenDrainPort *))temp.input.read;
    temp.set_bit = (void (*)(OpenDrainPort *))temp.output.set_bit;
    temp.reset_bit = (void (*)(OpenDrainPort *))temp.output.reset_bit;
    temp.toggle = (void (*)(OpenDrainPort *))temp.output.toggle;
    temp.init(&temp);
    return temp;
}

static void _l_on(LED *led)
{
    if(led->level)
    {
        led->outputport.set_bit(&led->outputport);
    }else{
        led->outputport.reset_bit(&led->outputport);
    }
}

static void _l_off(LED *led)
{
    if(led->level)
    {
        led->outputport.reset_bit(&led->outputport);
    }else{
        led->outputport.set_bit(&led->outputport);
    }
}

LED new_led(uint32_t gpiox,uint32_t gpio_pinx,uint8_t level)
{
    LED temp;
    temp.level = level;
    temp.outputport = new_outport(gpiox,gpio_pinx);
    temp.toggle =(void(*)(LED *))temp.outputport.toggle;
    temp.on = _l_on;
    temp.off = _l_off;
    temp.outputport.init(&temp.outputport);
    return temp;
}
#endif
#ifdef USE_UART
/***************************************************************************************************
* UART API
*/

static void _uart_init(UART *uart)
{
    switch(uart->uartx)
    {
        case USART0: rcu_periph_clock_enable(RCU_USART0);nvic_irq_enable(USART0_IRQn, 7, 0);break;
        case USART1: rcu_periph_clock_enable(RCU_USART1);nvic_irq_enable(USART1_IRQn, 7, 0);break;
#ifndef GD32F3X0
        case USART2: rcu_periph_clock_enable(RCU_USART2);nvic_irq_enable(USART2_IRQn, 7, 0);break;
        case UART3: rcu_periph_clock_enable(RCU_UART3);nvic_irq_enable(UART3_IRQn, 7, 0);break;
        case UART4: rcu_periph_clock_enable(RCU_UART4);nvic_irq_enable(UART4_IRQn, 7, 0);break;
#ifndef GD32F10X       
        case USART5: rcu_periph_clock_enable(RCU_USART5);nvic_irq_enable(USART5_IRQn, 7, 0);break;
        case UART6: rcu_periph_clock_enable(RCU_UART6);nvic_irq_enable(UART6_IRQn, 7, 0);break;
        case UART7: rcu_periph_clock_enable(RCU_UART7);nvic_irq_enable(UART7_IRQn, 7, 0);break;
#endif
#endif
        default :break;
    }

    /* USART configure */
    usart_deinit(uart->uartx);
    usart_baudrate_set(uart->uartx,uart->baudrate);
    usart_receive_config(uart->uartx, USART_RECEIVE_ENABLE);
    usart_transmit_config(uart->uartx, USART_TRANSMIT_ENABLE);
    usart_enable(uart->uartx);
}

static void _uart_senddata(UART *uart,uint8_t buf)
{
    while (!usart_flag_get(uart->uartx, USART_FLAG_TBE) && !usart_flag_get(uart->uartx, USART_FLAG_TC));
    usart_data_transmit(uart->uartx,buf);
}

static void _uart_sendbuf(UART *uart,uint8_t *buf, uint16_t size)
{
	for (uint16_t i = 0; i < size; i++)
	{
		while (!usart_flag_get(uart->uartx, USART_FLAG_TBE) && !usart_flag_get(uart->uartx, USART_FLAG_TC));
		usart_data_transmit(uart->uartx,buf[i]);
	}
}

static void _uart_sendString(UART *uart,uint8_t *buf)
{
	while (*buf != 0)
	{
		while (!usart_flag_get(uart->uartx, USART_FLAG_TBE) && !usart_flag_get(uart->uartx, USART_FLAG_TC));
		usart_data_transmit(uart->uartx,*buf);
        if(uart->uartx != USART0)usart_data_transmit(USART0,*buf);
        buf++;
	}
}

#ifdef USE_PRINTF
static void  _uart_printf(UART *uart, const char* fmt, ...)
{
	uint16_t len;
	char printfbuf[300];
	memset(printfbuf, 0, 300);
	va_list ap;
	va_start(ap, fmt);
	len = vsprintf(printfbuf, fmt, ap);
	va_end(ap);
	_uart_sendbuf(uart, (uint8_t*)printfbuf, len);
}
#endif
static void  _uart_RecvIT(UART *uart,uint8_t *buf,uint16_t size,uint8_t timeout)
{
    if(0 == size){
        return ;
    }
    if(0 != buf)
    {
        memset(buf,0,size);
    }
#ifdef CMSIS_OS
    /* create a binary semaphore used for informing ethernetif of frame reception */
    if(0 == uart->uart_recv_sem)
    {
        osSemaphoreDef(SEM_UART_RX);
        uart->uart_recv_sem = osSemaphoreCreate(osSemaphore(SEM_UART_RX) , 1 );
        osSemaphoreWait(uart->uart_recv_sem,timeout);  
    }
#endif
    uart->recvbuf = buf;
    uart->recvsize = size;
    uart->recvcnt = 0;
    uart->isgetrecv = 0;
#if !defined(GD32F10X)
#if !defined(GD32F3X0)
    if(uart->uartx < UART3 || uart->uartx > UART7)
#endif
    {
#if defined(GD32F3X0)
			//usart_receiver_timeout_config(uart->uartx, timeout);
            uart->rxtimeoutset = timeout;
#else
        usart_receiver_timeout_threshold_config(uart->uartx, timeout);
#endif
        usart_receiver_timeout_enable(uart->uartx);
        usart_interrupt_enable(uart->uartx, USART_INT_RT); 
    }
#endif
		usart_interrupt_enable(uart->uartx, USART_INT_RBNE);
		usart_interrupt_flag_clear(uart->uartx, USART_INT_FLAG_RBNE);
    
}

#ifdef CMSIS_OS
static uint8_t _uart_waitforrecv(UART *uart,uint32_t waittime)
{
    return osSemaphoreWait( uart->uart_recv_sem, waittime);
}
#endif

void Uart_timeout_Handle(UART *uart)
{
    if(uart->rxtimeoutcnt)
    {
        uart->rxtimeoutcnt++;
        if(uart->rxtimeoutcnt > uart->rxtimeoutset)
        {
            uart->rxtimeoutcnt = 0;
            uart->isgetrecv = 1;
        }
    }
}

static void  _uart_RecvFixCntIT(UART *uart,uint8_t *buf,uint16_t size)
{
    if(0 == size){
        return ;
    }
    if(0 != buf)
    {
        memset(buf,0,size);
    }
#ifdef CMSIS_OS
    /* create a binary semaphore used for informing ethernetif of frame reception */
    if(0 == uart->uart_recv_sem)
    {
        osSemaphoreDef(SEM_UART_RX);
        uart->uart_recv_sem = osSemaphoreCreate(osSemaphore(SEM_UART_RX) , 1 );
        osSemaphoreWait(uart->uart_recv_sem,timeout);  
    }
#endif
    uart->recvbuf = buf;
    uart->recvsize = size;
    uart->recvcnt = 0;
    uart->isgetrecv = 0;
    uart->RecvMode = RECV_MODE_FIX_IT;
  /* Enable RXNE and Error interrupts */
		usart_interrupt_enable(uart->uartx, USART_INT_RBNE);
		usart_interrupt_flag_clear(uart->uartx, USART_INT_FLAG_RBNE);
}

void Uart_Interrupt_Handle(UART *uart)
{
    uint8_t temp;
    if(RESET != usart_interrupt_flag_get(uart->uartx, USART_INT_FLAG_RBNE))
    {
        usart_interrupt_flag_clear(uart->uartx, USART_INT_FLAG_RBNE);
    /* receive data */
        if(uart->recvcnt < uart->recvsize)
        {
            temp = (usart_data_receive(uart->uartx) & 0xFF);
            *(uart->recvbuf++) = temp;
            usart_data_transmit(USART0,temp);
            uart->recvcnt++;
            uart->rxtimeoutcnt = 1;
        }
    }
//#if !defined(GD32F10X) 
#ifndef GD32F3X0
    if(uart->uartx >= UART3 && uart->uartx <= UART7)
    {
        if(uart->recvcnt == uart->recvsize)
        {
            uart->isgetrecv = 1;
#ifdef CMSIS_OS
            osSemaphoreRelease(uart->uart_recv_sem);  
#endif
            usart_interrupt_disable(uart->uartx, USART_INT_RBNE);

        }
    }
    else{

        if(RESET != usart_interrupt_flag_get(uart->uartx, USART_INT_FLAG_RT))
        {
            usart_interrupt_flag_clear(uart->uartx, USART_INT_FLAG_RT);
            uart->isgetrecv = 1;
#ifdef CMSIS_OS
            osSemaphoreRelease(uart->uart_recv_sem);  
#endif
            usart_interrupt_disable(uart->uartx, USART_INT_RBNE);
            usart_interrupt_disable(uart->uartx, USART_INT_RT);  
        }

    }

#else
		if(uart->recvcnt == uart->recvsize)
        {
            uart->isgetrecv = 1;
#ifdef CMSIS_OS
            //osSemaphoreRelease(uart->uart_recv_sem);  
#endif
            usart_interrupt_disable(uart->uartx, USART_INT_RBNE);

        }
#endif
		 if(RESET != usart_interrupt_flag_get(uart->uartx, USART_INT_FLAG_RBNE_ORERR))
    {
        usart_interrupt_flag_clear(uart->uartx, USART_INT_FLAG_RBNE_ORERR);
    }
}

static  void _uart_SetRecvCallBack(UART *uart,pfun callback,void *arg)
{
    if(callback != NULL) uart->RecvCallBack = callback;
    if(arg != NULL)uart->RecvCBArg = arg;
}

UART new_uart(uint32_t txd_gpiox,uint32_t txd_gpio_pinx,uint32_t rxd_gpiox,uint32_t rxd_gpio_pinx,uint32_t uartx,uint32_t baudrate)
{
    UART temp;
#if defined(GD32F10X) ||defined(GD32F20X)
    temp.txd_pin = new_afio_gpio(txd_gpiox,txd_gpio_pinx,0);
    temp.rxd_pin = new_inputport(rxd_gpiox,rxd_gpio_pinx,GPIO_MODE_IN_FLOATING,0);
#else
	   temp.txd_pin = new_afio_gpio(txd_gpiox,txd_gpio_pinx,GPIO_AF_1);
    temp.rxd_pin = new_afio_gpio(rxd_gpiox,rxd_gpio_pinx,GPIO_AF_1);
#endif
    temp.uartx = uartx;
    temp.baudrate = baudrate;
    temp.init = _uart_init;
    temp.senddata = _uart_senddata;
    temp.sendbuf = _uart_sendbuf;
#ifdef USE_PRINTF
    temp.printf = _uart_printf;
#endif
    temp.sendString=_uart_sendString;
    temp.RecvFixCntIT = _uart_RecvFixCntIT;
    temp.SetRecvCallBack = _uart_SetRecvCallBack;
    temp.RecvTimeoutIT = _uart_RecvIT;
    temp.RecvCallBack = NULL;
    temp.RecvCBArg = NULL;
#ifdef CMSIS_OS
    temp.uart_recv_sem = NULL;
    temp.WaitforRecv = _uart_waitforrecv;
#endif
    temp.init(&temp);
    return temp;
}
#endif
#ifdef USE_SPI
static void _s_init(SPI *spi)
{
    spi_parameter_struct spi_init_struct;

    switch(spi->spix)
    {
        case SPI0: rcu_periph_clock_enable(RCU_SPI0);break;
        case SPI1: rcu_periph_clock_enable(RCU_SPI1);break;
        case SPI2: rcu_periph_clock_enable(RCU_SPI2);break;
        default:break;
    }
   
    /* SPI parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
		if(spi->mode !=0)
		spi_init_struct.clock_polarity_phase = spi->mode;
		else
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = spi->buadrate;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(spi->spix, &spi_init_struct);
    spi_enable(spi->spix);
}

static uint16_t _s_readwritebyte(SPI* spi,uint16_t byte)
{
    uint8_t retry = 0;
    while(RESET == spi_i2s_flag_get(spi->spix, SPI_FLAG_TBE));
   {
       retry++;
       if(retry >200)return 0;
   }
    spi_i2s_data_transmit(spi->spix,byte);
    retry = 0;
    while(RESET == spi_i2s_flag_get(spi->spix, SPI_FLAG_RBNE));
       {
       retry++;
       if(retry >200)return 0;
   }
    return spi_i2s_data_receive(spi->spix);
}

static void _s_setspeed(SPI* spi,uint32_t baud)
{
    // if(baud >CTL0_PSC(7) || baud< CTL0_PSC(0))   //error baudrate
    // return;
    SPI_CTL0(spi->spix) &= 0xFFC7;
    SPI_CTL0(spi->spix) |= baud;
}

static void _s_set_frame_bit(SPI* spi,uint16_t framebit)
{
    spi_i2s_data_frame_format_config(spi->spix,framebit);
}

#if defined(GD32F20X) || defined(GD32F4X0)
static void _s_quad_spi_init(SPI *spi,uint32_t spi_gpio,uint32_t spi_io2_pinx,uint32_t spi_io3_pinx)
{
    if(spi->spix != SPI0) return; 
    AFIO_GPIO spi_io2 = new_afio_gpio(spi_gpio,spi_io2_pinx,0);
    AFIO_GPIO spi_io3 = new_afio_gpio(spi_gpio,spi_io3_pinx,0);
    /* enable quad wire SPI_IO2 and SPI_IO3 pin output */
    qspi_io23_output_enable(SPI0);
}
#endif
SPI new_spi(uint32_t gpiox,uint32_t sck_pinx,uint32_t miso_pinx,uint32_t mosi_pinx,uint32_t spix)
{
    SPI temp;
#if defined(GD32F4XX)

#elif defined(GD32F10X) ||  defined(GD32F20X)
    if(spix == SPI0 && gpiox == GPIOB)
    {
        rcu_periph_clock_enable(RCU_AF);
         gpio_pin_remap_config(GPIO_SPI0_REMAP,ENABLE);
    }
    temp.sck = new_afio_gpio(gpiox,sck_pinx,0);
    temp.miso = new_afio_gpio(gpiox,miso_pinx,0);
    temp.mosi = new_afio_gpio(gpiox,mosi_pinx,0);
#endif
    temp.spix = spix;
    temp.buadrate = SPI_PSC_32;
    temp.init = _s_init;
    temp.readwritebyte = _s_readwritebyte;
    temp.SetSpeed = _s_setspeed;
    temp.Set_Frame_Bit = _s_set_frame_bit;
#if defined(GD32F20X) || defined(GD32F4X0)
    temp.Quadspi_init = _s_quad_spi_init;
#endif
    temp.init(&temp);
    return temp;
}
#endif
void WatchDog_init(void)
{
    /* confiure FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz */
    fwdgt_config(4000,FWDGT_PSC_DIV256);     //500 * 1/ 625  = 0.8s 
    
    /* After 1.6 seconds to generate a reset */
    fwdgt_enable();
	
	    /* check if the system has resumed from FWDGT reset */
    if (RESET != rcu_flag_get(RCU_FLAG_FWDGTRST)){

        rcu_all_reset_flag_clear();
        //log_info("Reset by WatchDOg");      
    }
}

void Freedog(void)
{
	fwdgt_counter_reload();
}

#ifdef GD32F20X
#define FLASHSIZE_BASE        0x1FFFF7E0    /*!< FLASH Size register base address */
#define UNIQUE_ID_BASE        0x1FFFF7E8U
#endif
uint32_t GetFlashSize(void)
{
  return (uint32_t)(REG16(FLASHSIZE_BASE));
}
uint32_t GetSramSize(void)
{
    return (uint32_t)(REG16(FLASHSIZE_BASE +2));
}

uint32_t GetCPUID(void)
{
    return (SCB->CPUID);
}

void GetMCUUID(uint32_t *UID)
{
  UID[0] = (uint32_t)(REG32(UNIQUE_ID_BASE));
  UID[1] = (uint32_t)(REG32(UNIQUE_ID_BASE + 4U));
  UID[2] = (uint32_t)(REG32(UNIQUE_ID_BASE + 8U));
}
